/**
 * @file database_health.cpp
 * @brief 数据库健康检查实现
 * @author liyingcheng <1871304538@qq.com>
 * @date 2025-10-12
 */

#include "database/database_health.h"
#include "database/mysql_pool.h"
#include "database/redis_pool.h"
#include "LoggerManager.h"
#include <cppconn/exception.h>
#include <sstream>

namespace cpp_backend
{
    namespace database
    {

        using namespace logger;

        // ============================================
        // HealthCheckResult 实现
        // ============================================

        nlohmann::json HealthCheckResult::ToJson() const
        {
            return nlohmann::json{
                {"status", DatabaseHealthChecker::StatusToString(status)},
                {"message", message},
                {"response_time_ms", response_time_ms},
                {"timestamp", std::chrono::duration_cast<std::chrono::seconds>(
                                  timestamp.time_since_epoch())
                                  .count()},
                {"details", details}};
        }

        // ============================================
        // MySQLHealthResult 实现
        // ============================================

        nlohmann::json MySQLHealthResult::ToJson() const
        {
            auto base = HealthCheckResult::ToJson();
            base["total_connections"] = total_connections;
            base["active_connections"] = active_connections;
            base["idle_connections"] = idle_connections;
            base["can_connect"] = can_connect;
            base["can_query"] = can_query;
            return base;
        }

        // ============================================
        // RedisHealthResult 实现
        // ============================================

        nlohmann::json RedisHealthResult::ToJson() const
        {
            auto base = HealthCheckResult::ToJson();
            base["total_connections"] = total_connections;
            base["active_connections"] = active_connections;
            base["idle_connections"] = idle_connections;
            base["can_connect"] = can_connect;
            base["can_ping"] = can_ping;
            base["redis_version"] = redis_version;
            base["used_memory"] = used_memory;
            return base;
        }

        // ============================================
        // DatabaseHealthChecker 实现
        // ============================================

        DatabaseHealthChecker &DatabaseHealthChecker::Instance()
        {
            static DatabaseHealthChecker instance;
            return instance;
        }

        MySQLHealthResult DatabaseHealthChecker::CheckMySQL()
        {
            MySQLHealthResult result;
            result.timestamp = std::chrono::system_clock::now();

            try
            {
                LOG_DEBUG << "Checking MySQL health...";

                // 获取连接池统计信息
                auto stats = MySQLPool::Instance().GetStats();
                result.total_connections = stats.total_connections;
                result.active_connections = stats.active_connections;
                result.idle_connections = stats.available_connections;

                // 测试连接
                int64_t connect_time = 0;
                result.can_connect = TestMySQLConnection(connect_time);

                if (!result.can_connect)
                {
                    result.status = HealthStatus::UNHEALTHY;
                    result.message = "Cannot connect to MySQL";
                    result.response_time_ms = connect_time;
                    LOG_WARN << "MySQL health check failed: cannot connect";
                    return result;
                }

                // 测试查询
                int64_t query_time = 0;
                result.can_query = TestMySQLQuery(query_time);
                result.response_time_ms = connect_time + query_time;

                if (!result.can_query)
                {
                    result.status = HealthStatus::DEGRADED;
                    result.message = "MySQL connected but query failed";
                    LOG_WARN << "MySQL health check degraded: query failed";
                    return result;
                }

                // 检查响应时间
                if (result.response_time_ms > 1000)
                { // 超过1秒认为性能降级
                    result.status = HealthStatus::DEGRADED;
                    result.message = "MySQL response time too slow";
                    LOG_WARN << "MySQL health check degraded: slow response ("
                             << result.response_time_ms << "ms)";
                }
                else
                {
                    result.status = HealthStatus::HEALTHY;
                    result.message = "MySQL is healthy";
                    LOG_DEBUG << "MySQL health check passed ("
                              << result.response_time_ms << "ms)";
                }
            }
            catch (const std::exception &e)
            {
                result.status = HealthStatus::UNHEALTHY;
                result.message = std::string("MySQL health check exception: ") + e.what();
                LOG_ERROR << result.message;
            }

            return result;
        }

        RedisHealthResult DatabaseHealthChecker::CheckRedis()
        {
            RedisHealthResult result;
            result.timestamp = std::chrono::system_clock::now();

            try
            {
                LOG_DEBUG << "Checking Redis health...";

                // 获取Redis连接池统计信息
                auto stats = RedisPool::Instance().GetStatistics();
                result.total_connections = stats.total_count;
                result.active_connections = stats.active_count;
                result.idle_connections = stats.idle_count;

                // 测试连接
                int64_t connect_time = 0;
                result.can_connect = TestRedisConnection(connect_time);

                if (!result.can_connect)
                {
                    result.status = HealthStatus::UNHEALTHY;
                    result.message = "Cannot connect to Redis";
                    result.response_time_ms = connect_time;
                    LOG_WARN << "Redis health check failed: cannot connect";
                    return result;
                }

                // 测试Ping
                int64_t ping_time = 0;
                result.can_ping = TestRedisPing(ping_time);
                result.response_time_ms = connect_time + ping_time;

                if (!result.can_ping)
                {
                    result.status = HealthStatus::DEGRADED;
                    result.message = "Redis connected but ping failed";
                    LOG_WARN << "Redis health check degraded: ping failed";
                    return result;
                }

                // 获取Redis信息
                GetRedisInfo(result.redis_version, result.used_memory);

                // 检查响应时间
                if (result.response_time_ms > 500)
                { // 超过500ms认为性能降级
                    result.status = HealthStatus::DEGRADED;
                    result.message = "Redis response time too slow";
                    LOG_WARN << "Redis health check degraded: slow response ("
                             << result.response_time_ms << "ms)";
                }
                else
                {
                    result.status = HealthStatus::HEALTHY;
                    result.message = "Redis is healthy";
                    LOG_DEBUG << "Redis health check passed ("
                              << result.response_time_ms << "ms)";
                }
            }
            catch (const std::exception &e)
            {
                result.status = HealthStatus::UNHEALTHY;
                result.message = std::string("Redis health check exception: ") + e.what();
                LOG_ERROR << result.message;
            }

            return result;
        }

        HealthCheckResult DatabaseHealthChecker::CheckAll()
        {
            HealthCheckResult result;
            result.timestamp = std::chrono::system_clock::now();

            auto start = std::chrono::steady_clock::now();

            // 检查MySQL
            auto mysql_result = CheckMySQL();

            // 检查Redis
            auto redis_result = CheckRedis();

            auto end = std::chrono::steady_clock::now();
            result.response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                          end - start)
                                          .count();

            // 汇总结果
            nlohmann::json details;
            details["mysql"] = mysql_result.ToJson();
            details["redis"] = redis_result.ToJson();
            result.details = details;

            // 确定总体状态
            if (!mysql_result.IsHealthy() || !redis_result.IsHealthy())
            {
                if (mysql_result.status == HealthStatus::UNHEALTHY ||
                    redis_result.status == HealthStatus::UNHEALTHY)
                {
                    result.status = HealthStatus::UNHEALTHY;
                    result.message = "One or more databases are unhealthy";
                }
                else
                {
                    result.status = HealthStatus::DEGRADED;
                    result.message = "One or more databases are degraded";
                }
            }
            else
            {
                result.status = HealthStatus::HEALTHY;
                result.message = "All databases are healthy";
            }

            LOG_INFO << "Database health check completed: " << result.message
                     << " (" << result.response_time_ms << "ms)";

            return result;
        }

        std::string DatabaseHealthChecker::StatusToString(HealthStatus status)
        {
            switch (status)
            {
            case HealthStatus::HEALTHY:
                return "healthy";
            case HealthStatus::DEGRADED:
                return "degraded";
            case HealthStatus::UNHEALTHY:
                return "unhealthy";
            case HealthStatus::UNKNOWN:
                return "unknown";
            default:
                return "unknown";
            }
        }

        bool DatabaseHealthChecker::TestMySQLConnection(int64_t &response_time_ms)
        {
            auto start = std::chrono::steady_clock::now();

            try
            {
                MySQLConnectionGuard guard(1000); // 1秒超时
                if (!guard.IsValid())
                {
                    response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                           std::chrono::steady_clock::now() - start)
                                           .count();
                    return false;
                }

                response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                       std::chrono::steady_clock::now() - start)
                                       .count();
                return true;
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "MySQL connection test failed: " << e.what();
                response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                       std::chrono::steady_clock::now() - start)
                                       .count();
                return false;
            }
        }

        bool DatabaseHealthChecker::TestMySQLQuery(int64_t &response_time_ms)
        {
            auto start = std::chrono::steady_clock::now();

            try
            {
                MySQLConnectionGuard guard(1000);
                if (!guard.IsValid())
                {
                    response_time_ms = 0;
                    return false;
                }

                // 执行简单查询
                std::unique_ptr<sql::Statement> stmt(guard->createStatement());
                std::unique_ptr<sql::ResultSet> res(stmt->executeQuery("SELECT 1"));

                bool success = res && res->next();

                response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                       std::chrono::steady_clock::now() - start)
                                       .count();

                return success;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "MySQL query test failed: " << e.what();
                response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                       std::chrono::steady_clock::now() - start)
                                       .count();
                return false;
            }
        }

        bool DatabaseHealthChecker::TestRedisConnection(int64_t &response_time_ms)
        {
            auto start = std::chrono::steady_clock::now();

            try
            {
                auto &pool = RedisPool::Instance();
                RedisConnectionGuard guard(pool, 1000); // 1秒超时

                if (!guard.IsValid())
                {
                    response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                           std::chrono::steady_clock::now() - start)
                                           .count();
                    return false;
                }

                response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                       std::chrono::steady_clock::now() - start)
                                       .count();
                return true;
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "Redis connection test failed: " << e.what();
                response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                       std::chrono::steady_clock::now() - start)
                                       .count();
                return false;
            }
        }

        bool DatabaseHealthChecker::TestRedisPing(int64_t &response_time_ms)
        {
            auto start = std::chrono::steady_clock::now();

            try
            {
                auto &pool = RedisPool::Instance();
                RedisConnectionGuard guard(pool, 1000);

                if (!guard.IsValid())
                {
                    response_time_ms = 0;
                    return false;
                }

                // 执行PING命令
                bool success = guard->Ping();

                response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                       std::chrono::steady_clock::now() - start)
                                       .count();

                return success;
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "Redis ping test failed: " << e.what();
                response_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                                       std::chrono::steady_clock::now() - start)
                                       .count();
                return false;
            }
        }

        bool DatabaseHealthChecker::GetRedisInfo(std::string &version, int64_t &used_memory)
        {
            try
            {
                auto &pool = RedisPool::Instance();
                RedisConnectionGuard guard(pool, 1000);

                if (!guard.IsValid())
                {
                    version = "未知";
                    used_memory = 0;
                    return false;
                }

                // 获取Redis INFO命令的输出
                std::string info_output;
                if (!guard->GetInfo(info_output))
                {
                    version = "未知";
                    used_memory = 0;
                    return false;
                }

                // 解析INFO输出
                std::istringstream iss(info_output);
                std::string line;

                while (std::getline(iss, line))
                {
                    // 去除行尾的\r
                    if (!line.empty() && line.back() == '\r')
                    {
                        line.pop_back();
                    }

                    // 解析redis_version
                    if (line.find("redis_version:") == 0)
                    {
                        version = line.substr(14); // 跳过"redis_version:"
                    }
                    // 解析used_memory
                    else if (line.find("used_memory:") == 0)
                    {
                        std::string mem_str = line.substr(12);
                        try
                        {
                            used_memory = std::stoll(mem_str);
                        }
                        catch (...)
                        {
                            used_memory = 0;
                        }
                    }
                }

                if (version.empty())
                {
                    version = "未知";
                }

                return true;
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "Get Redis info failed: " << e.what();
                version = "未知";
                used_memory = 0;
                return false;
            }
        }

    } // namespace database
} // namespace file_server
